import Foundation
import UIKit
import Display
import AsyncDisplayKit
import SwiftSignalKit
import AccountContext
import TelegramPresentationData
import ItemListUI
import SolidRoundedButtonNode
import AnimatedAvatarSetNode
import ShimmerEffect
import TelegramCore
import Markdown
import TextFormat
import ComponentFlow
import MultilineTextComponent
import TextNodeWithEntities

private func actionButtonImage(color: UIColor) -> UIImage? {
    return generateImage(CGSize(width: 24.0, height: 24.0), contextGenerator: { size, context in
        context.clear(CGRect(origin: CGPoint(), size: size))
        
        context.setFillColor(color.cgColor)
        context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
        
        context.setBlendMode(.clear)
        context.fillEllipse(in: CGRect(origin: CGPoint(x: 4.0, y: 10.0), size: CGSize(width: 4.0, height: 4.0)))
        context.fillEllipse(in: CGRect(origin: CGPoint(x: 10.0, y: 10.0), size: CGSize(width: 4.0, height: 4.0)))
        context.fillEllipse(in: CGRect(origin: CGPoint(x: 16.0, y: 10.0), size: CGSize(width: 4.0, height: 4.0)))
    })
}

public class ItemListPermanentInviteLinkItem: ListViewItem, ItemListItem {
    let context: AccountContext
    let presentationData: ItemListPresentationData
    let invite: ExportedInvitation?
    let count: Int32
    let peers: [EnginePeer]
    let displayButton: Bool
    let separateButtons: Bool
    let displayImporters: Bool
    let isCall: Bool
    let buttonColor: UIColor?
    public let sectionId: ItemListSectionId
    let style: ItemListStyle
    let copyAction: (() -> Void)?
    let shareAction: (() -> Void)?
    let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
    let viewAction: (() -> Void)?
    let openCallAction: (() -> Void)?
    public let tag: ItemListItemTag?
    
    public init(
        context: AccountContext,
        presentationData: ItemListPresentationData,
        invite: ExportedInvitation?,
        count: Int32,
        peers: [EnginePeer],
        displayButton: Bool,
        separateButtons: Bool = false,
        displayImporters: Bool,
        isCall: Bool = false,
        buttonColor: UIColor?,
        sectionId: ItemListSectionId,
        style: ItemListStyle,
        copyAction: (() -> Void)?,
        shareAction: (() -> Void)?,
        contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?,
        viewAction: (() -> Void)?,
        openCallAction: (() -> Void)?,
        tag: ItemListItemTag? = nil
    ) {
        self.context = context
        self.presentationData = presentationData
        self.invite = invite
        self.count = count
        self.peers = peers
        self.displayButton = displayButton
        self.separateButtons = separateButtons
        self.displayImporters = displayImporters
        self.isCall = isCall
        self.buttonColor = buttonColor
        self.sectionId = sectionId
        self.style = style
        self.copyAction = copyAction
        self.shareAction = shareAction
        self.contextAction = contextAction
        self.viewAction = viewAction
        self.openCallAction = openCallAction
        self.tag = tag
    }
    
    public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
        async {
            let node = ItemListPermanentInviteLinkItemNode()
            let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
            
            node.contentSize = layout.contentSize
            node.insets = layout.insets
            
            Queue.mainQueue().async {
                completion(node, {
                    return (nil, { _ in apply() })
                })
            }
        }
    }
    
    public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
        Queue.mainQueue().async {
            if let nodeValue = node() as? ItemListPermanentInviteLinkItemNode {
                let makeLayout = nodeValue.asyncLayout()
                
                async {
                    let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
                    Queue.mainQueue().async {
                        completion(layout, { _ in
                            apply()
                        })
                    }
                }
            }
        }
    }
    
    public var selectable: Bool = false
}

public class ItemListPermanentInviteLinkItemNode: ListViewItemNode, ItemListItemNode {
    private let backgroundNode: ASDisplayNode
    private let topStripeNode: ASDisplayNode
    private let bottomStripeNode: ASDisplayNode
    private let maskNode: ASImageNode
    
    private let fieldNode: ASImageNode
    private let addressNode: TextNode
    private let fieldButtonNode: HighlightTrackingButtonNode
    private let referenceContainerNode: ContextReferenceContentNode
    private let containerNode: ContextControllerSourceNode
    private let addressButtonNode: HighlightTrackingButtonNode
    private let addressButtonIconNode: ASImageNode
    private var addressShimmerNode: ShimmerEffectNode?
    private var copyButtonNode: SolidRoundedButtonNode?
    private var shareButtonNode: SolidRoundedButtonNode?
    
    private let avatarsButtonNode: HighlightTrackingButtonNode
    private let avatarsContext: AnimatedAvatarSetContext
    private var avatarsContent: AnimatedAvatarSetContext.Content?
    private let avatarsNode: AnimatedAvatarSetNode
    private let invitedPeersNode: TextNode
    private var shimmerNode: ShimmerEffectNode?
    private var absoluteLocation: (CGRect, CGSize)?
    
    private var justCreatedCallTextNode: TextNodeWithEntities?
    private var justCreatedCallLeftSeparatorLayer: SimpleLayer?
    private var justCreatedCallRightSeparatorLayer: SimpleLayer?
    private var justCreatedCallSeparatorText: ComponentView<Empty>?
    
    private let activateArea: AccessibilityAreaNode
    
    private var item: ItemListPermanentInviteLinkItem?
    
    override public var canBeSelected: Bool {
        return false
    }
    
    public var tag: ItemListItemTag? {
        return self.item?.tag
    }
    
    public init() {
        self.backgroundNode = ASDisplayNode()
        self.backgroundNode.isLayerBacked = true
        self.backgroundNode.backgroundColor = .white
        
        self.maskNode = ASImageNode()
        
        self.topStripeNode = ASDisplayNode()
        self.topStripeNode.isLayerBacked = true
        
        self.bottomStripeNode = ASDisplayNode()
        self.bottomStripeNode.isLayerBacked = true
        
        self.fieldNode = ASImageNode()
        self.fieldNode.displaysAsynchronously = false
        self.fieldNode.displayWithoutProcessing = true
        
        self.addressNode = TextNode()
        self.addressNode.isUserInteractionEnabled = false
        
        self.fieldButtonNode = HighlightTrackingButtonNode()
    
        self.containerNode = ContextControllerSourceNode()
        self.containerNode.animateScale = false
        self.referenceContainerNode = ContextReferenceContentNode()
        
        self.addressButtonNode = HighlightTrackingButtonNode()
        self.addressButtonIconNode = ASImageNode()
        self.addressButtonIconNode.contentMode = .center
        self.addressButtonIconNode.displaysAsynchronously = false
        self.addressButtonIconNode.displayWithoutProcessing = true
        
        self.avatarsButtonNode = HighlightTrackingButtonNode()
        self.avatarsContext = AnimatedAvatarSetContext()
        self.avatarsNode = AnimatedAvatarSetNode()
        self.invitedPeersNode = TextNode()
                
        self.activateArea = AccessibilityAreaNode()
        
        super.init(layerBacked: false, dynamicBounce: false)
        
        self.addSubnode(self.fieldNode)
        self.addSubnode(self.addressNode)
        self.addSubnode(self.fieldButtonNode)
        self.addSubnode(self.avatarsNode)
        self.addSubnode(self.invitedPeersNode)
        self.addSubnode(self.avatarsButtonNode)
        
        self.containerNode.addSubnode(self.referenceContainerNode)
        self.referenceContainerNode.addSubnode(self.addressButtonIconNode)
        self.referenceContainerNode.addSubnode(self.addressButtonNode)
        self.addSubnode(self.containerNode)
        
        self.addSubnode(self.activateArea)
        
        self.containerNode.activated = { [weak self] gesture, _ in
            if let strongSelf = self, let item = strongSelf.item {
                item.contextAction?(strongSelf.referenceContainerNode, gesture)
            }
        }
        
        self.fieldButtonNode.highligthedChanged = { [weak self] highlighted in
            if let strongSelf = self {
                if highlighted {
                    strongSelf.addressNode.layer.removeAnimation(forKey: "opacity")
                    strongSelf.addressNode.alpha = 0.4
                } else {
                    strongSelf.addressNode.alpha = 1.0
                    strongSelf.addressNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
                }
            }
        }
        self.fieldButtonNode.addTarget(self, action: #selector(self.fieldButtonPressed), forControlEvents: .touchUpInside)
        
        self.addressButtonNode.addTarget(self, action: #selector(self.addressButtonPressed), forControlEvents: .touchUpInside)
        self.addressButtonNode.highligthedChanged = { [weak self] highlighted in
            if let strongSelf = self {
                if highlighted {
                    strongSelf.addressButtonIconNode.layer.removeAnimation(forKey: "opacity")
                    strongSelf.addressButtonIconNode.alpha = 0.4
                } else {
                    strongSelf.addressButtonIconNode.alpha = 1.0
                    strongSelf.addressButtonIconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
                }
            }
        }
        self.copyButtonNode?.pressed = { [weak self] in
            if let strongSelf = self, let item = strongSelf.item {
                item.copyAction?()
            }
        }
        self.shareButtonNode?.pressed = { [weak self] in
            if let strongSelf = self, let item = strongSelf.item {
                item.shareAction?()
            }
        }
        self.avatarsButtonNode.highligthedChanged = { [weak self] highlighted in
            if let strongSelf = self {
                if highlighted {
                    strongSelf.avatarsNode.layer.removeAnimation(forKey: "opacity")
                    strongSelf.invitedPeersNode.layer.removeAnimation(forKey: "opacity")
                    strongSelf.avatarsNode.alpha = 0.4
                    strongSelf.invitedPeersNode.alpha = 0.4
                } else {
                    strongSelf.avatarsNode.alpha = 1.0
                    strongSelf.invitedPeersNode.alpha = 1.0
                    strongSelf.avatarsNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
                    strongSelf.invitedPeersNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
                }
            }
        }
        self.avatarsButtonNode.addTarget(self, action: #selector(self.avatarsButtonPressed), forControlEvents: .touchUpInside)
    }
    
    @objc private func fieldButtonPressed() {
        if let item = self.item {
            item.copyAction?()
        }
    }
    
    @objc private func addressButtonPressed() {
        if let item = self.item {
            item.contextAction?(self.referenceContainerNode, nil)
        }
    }
    
    @objc private func avatarsButtonPressed() {
        if let item = self.item {
            item.viewAction?()
        }
    }
    
    @objc private func justCreatedCallTextTap(_ recognizer: UITapGestureRecognizer) {
        if case .ended = recognizer.state {
            self.item?.openCallAction?()
        }
    }
    
    public func asyncLayout() -> (_ item: ItemListPermanentInviteLinkItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
        let makeAddressLayout = TextNode.asyncLayout(self.addressNode)
        let makeInvitedPeersLayout = TextNode.asyncLayout(self.invitedPeersNode)
        let makeJustCreatedCallTextNodeLayout = TextNodeWithEntities.asyncLayout(self.justCreatedCallTextNode)
        
        let currentItem = self.item
        let avatarsContext = self.avatarsContext
        
        return { item, params, neighbors in
            var updatedTheme: PresentationTheme?
            if currentItem?.presentationData.theme !== item.presentationData.theme {
                updatedTheme = item.presentationData.theme
            }
            
            let contentSize: CGSize
            let insets: UIEdgeInsets
            let separatorHeight = UIScreenPixel
            let itemBackgroundColor: UIColor
            let itemSeparatorColor: UIColor
            
            let leftInset = 16.0 + params.leftInset
            let rightInset = 16.0 + params.rightInset
            
            let titleColor: UIColor
            titleColor = item.presentationData.theme.list.itemInputField.primaryColor
            
            let alignCentrally = !(item.invite?.link?.contains("joinchat") ?? true)
            
            let addressFont = Font.regular(!alignCentrally && params.width == 320 ? floor(item.presentationData.fontSize.itemListBaseFontSize * 15.0 / 17.0) : item.presentationData.fontSize.itemListBaseFontSize)
            let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
            
            let constrainedWidth = alignCentrally ? params.width - leftInset - rightInset - 90.0 : params.width - leftInset - rightInset - 60.0
            
            let (addressLayout, addressApply) = makeAddressLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.invite.flatMap({ $0.link?.replacingOccurrences(of: "https://", with: "") }) ?? "", font: addressFont, textColor: titleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .middle, constrainedSize: CGSize(width: constrainedWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
            
            let subtitle: String
            let subtitleColor: UIColor
            if item.count > 0 {
                subtitle = item.presentationData.strings.InviteLink_PeopleJoined(item.count)
                subtitleColor = item.presentationData.theme.list.itemAccentColor
            } else {
                subtitle = item.presentationData.strings.InviteLink_PeopleJoinedNone
                subtitleColor = item.presentationData.theme.list.itemSecondaryTextColor
            }
            
            let (invitedPeersLayout, invitedPeersApply) = makeInvitedPeersLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: subtitle, font: titleFont, textColor: subtitleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
            
            var justCreatedCallTextNodeLayout: (TextNodeLayout, (TextNodeWithEntities.Arguments?) -> TextNodeWithEntities?)?
            if item.isCall {
                let chevronImage = generateTintedImage(image: UIImage(bundleImageName: "Contact List/SubtitleArrow"), color: item.presentationData.theme.list.itemAccentColor)

                let textFont = Font.regular(15.0)
                let boldTextFont = Font.semibold(15.0)
                let textColor = item.presentationData.theme.list.itemPrimaryTextColor
                let accentColor = item.presentationData.theme.list.itemAccentColor
                let markdownAttributes = MarkdownAttributes(
                    body: MarkdownAttributeSet(font: textFont, textColor: textColor),
                    bold: MarkdownAttributeSet(font: boldTextFont, textColor: textColor),
                    link: MarkdownAttributeSet(font: textFont, textColor: accentColor),
                    linkAttribute: { contents in
                        return (TelegramTextAttributes.URL, contents)
                    }
                )
                let justCreatedCallTextAttributedString = parseMarkdownIntoAttributedString(item.presentationData.strings.InviteLink_CreatedGroupCallFooter, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString
                if let range = justCreatedCallTextAttributedString.string.range(of: ">"), let chevronImage {
                    justCreatedCallTextAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: justCreatedCallTextAttributedString.string))
                }

                justCreatedCallTextNodeLayout = makeJustCreatedCallTextNodeLayout(TextNodeLayoutArguments(
                    attributedString: justCreatedCallTextAttributedString,
                    backgroundColor: nil,
                    maximumNumberOfLines: 0,
                    truncationType: .end,
                    constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude),
                    alignment: .center,
                    lineSpacing: 0.28,
                    cutout: nil,
                    insets: UIEdgeInsets()
                ))
            }
            
            let avatarsContent = avatarsContext.update(peers: item.peers, animated: false)
            
            let verticalInset: CGFloat = 16.0
            let fieldHeight: CGFloat = 52.0
            let fieldSpacing: CGFloat = 16.0
            let buttonHeight: CGFloat = 50.0
            let justCreatedCallSeparatorSpacing: CGFloat = 16.0
            let justCreatedCallTextSpacing: CGFloat = 45.0
            
            var height = verticalInset * 2.0 + fieldHeight + fieldSpacing + buttonHeight + 54.0

            if let justCreatedCallTextNodeLayout {
                height += justCreatedCallTextSpacing - 2.0
                height += justCreatedCallTextNodeLayout.0.size.height
            }
            
            switch item.style {
            case .plain:
                itemBackgroundColor = item.presentationData.theme.list.plainBackgroundColor
                itemSeparatorColor = .clear
                insets = UIEdgeInsets()
            case .blocks:
                itemBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor
                itemSeparatorColor = item.presentationData.theme.list.itemBlocksSeparatorColor
                insets = itemListNeighborsGroupedInsets(neighbors, params)
            }
            
            if !item.displayImporters {
                height -= 57.0
            }
            if !item.displayButton {
                height -= 63.0
            }
            
            contentSize = CGSize(width: params.width, height: height)
            
            let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
            
            return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in
                if let strongSelf = self {
                    strongSelf.item = item
                    strongSelf.avatarsContent = avatarsContent
                    
                    strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height))
//                    strongSelf.activateArea.accessibilityLabel = item.title
//                    strongSelf.activateArea.accessibilityValue = item.label
                    strongSelf.activateArea.accessibilityTraits = []
                    
                    if let _ = updatedTheme {
                        strongSelf.topStripeNode.backgroundColor = itemSeparatorColor
                        strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor
                        strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
                        strongSelf.fieldNode.image = generateStretchableFilledCircleImage(diameter: 18.0, color: item.presentationData.theme.list.itemInputField.backgroundColor)
                        strongSelf.addressButtonIconNode.image = actionButtonImage(color: item.presentationData.theme.list.itemInputField.controlColor)
                    }
                                        
                    let _ = addressApply()
                    let _ = invitedPeersApply()
                    
                    switch item.style {
                    case .plain:
                        if strongSelf.backgroundNode.supernode != nil {
                            strongSelf.backgroundNode.removeFromSupernode()
                        }
                        if strongSelf.topStripeNode.supernode != nil {
                            strongSelf.topStripeNode.removeFromSupernode()
                        }
                        if strongSelf.bottomStripeNode.supernode == nil {
                            strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
                        }
                        if strongSelf.maskNode.supernode != nil {
                            strongSelf.maskNode.removeFromSupernode()
                        }
                        strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
                    case .blocks:
                        if strongSelf.backgroundNode.supernode == nil {
                            strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
                        }
                        if strongSelf.topStripeNode.supernode == nil {
                            strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1)
                        }
                        if strongSelf.bottomStripeNode.supernode == nil {
                            strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
                        }
                        if strongSelf.maskNode.supernode == nil {
                            strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
                        }
                        
                        let hasCorners = itemListHasRoundedBlockLayout(params)
                        var hasTopCorners = false
                        var hasBottomCorners = false
                        switch neighbors.top {
                            case .sameSection(false):
                                strongSelf.topStripeNode.isHidden = true
                            default:
                                hasTopCorners = true
                                strongSelf.topStripeNode.isHidden = hasCorners
                        }
                        let bottomStripeInset: CGFloat
                        switch neighbors.bottom {
                            case .sameSection(false):
                                bottomStripeInset = leftInset
                                strongSelf.bottomStripeNode.isHidden = false
                            default:
                                bottomStripeInset = 0.0
                                hasBottomCorners = true
                                strongSelf.bottomStripeNode.isHidden = hasCorners
                        }
                        
                        strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
                        
                        strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
                        strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
                        strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
                        strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
                    }
                    
                    let fieldFrame = CGRect(origin: CGPoint(x: leftInset, y: verticalInset), size: CGSize(width: params.width - leftInset - rightInset, height: fieldHeight))
                    strongSelf.fieldNode.frame = fieldFrame
                    strongSelf.fieldButtonNode.frame = fieldFrame
                    
                    strongSelf.addressNode.frame = CGRect(origin: CGPoint(x: fieldFrame.minX + (alignCentrally ? floorToScreenPixels((fieldFrame.width - addressLayout.size.width) / 2.0) : 14.0), y: fieldFrame.minY + floorToScreenPixels((fieldFrame.height - addressLayout.size.height) / 2.0) + 1.0), size: addressLayout.size)
                    
                    strongSelf.containerNode.frame = CGRect(origin: CGPoint(x: params.width - rightInset - 38.0 - 14.0, y: verticalInset), size: CGSize(width: 52.0, height: 52.0))
                    strongSelf.addressButtonNode.frame = strongSelf.containerNode.bounds
                    strongSelf.referenceContainerNode.frame =  strongSelf.containerNode.bounds
                    strongSelf.addressButtonIconNode.frame = strongSelf.containerNode.bounds
                    
                    strongSelf.addressButtonNode.isHidden = item.contextAction == nil
                    strongSelf.addressButtonIconNode.isHidden = item.contextAction == nil
                      
                    var effectiveSeparateButtons = item.separateButtons
                    if let invite = item.invite, invitationAvailability(invite).isZero {
                        effectiveSeparateButtons = false
                    }
                    
                    let copyButtonNode: SolidRoundedButtonNode
                    if let currentCopyButtonNode = strongSelf.copyButtonNode {
                        copyButtonNode = currentCopyButtonNode
                    } else {
                        let buttonTheme: SolidRoundedButtonTheme
                        if let buttonColor = item.buttonColor {
                            buttonTheme = SolidRoundedButtonTheme(backgroundColor: buttonColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor)
                        } else {
                            buttonTheme = SolidRoundedButtonTheme(theme: item.presentationData.theme)
                        }
                        copyButtonNode = SolidRoundedButtonNode(theme: buttonTheme, height: 50.0, cornerRadius: 11.0)
                        copyButtonNode.title = item.presentationData.strings.InviteLink_CopyShort
                        copyButtonNode.pressed = { [weak self] in
                            self?.item?.copyAction?()
                        }
                        strongSelf.addSubnode(copyButtonNode)
                        strongSelf.copyButtonNode = copyButtonNode
                    }
                    
                    let shareButtonNode: SolidRoundedButtonNode
                    if let currentShareButtonNode = strongSelf.shareButtonNode {
                        shareButtonNode = currentShareButtonNode
                    } else {
                        let buttonTheme: SolidRoundedButtonTheme
                        if let buttonColor = item.buttonColor {
                            buttonTheme = SolidRoundedButtonTheme(backgroundColor: buttonColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor)
                        } else {
                            buttonTheme = SolidRoundedButtonTheme(theme: item.presentationData.theme)
                        }
                        shareButtonNode = SolidRoundedButtonNode(theme: buttonTheme, height: 50.0, cornerRadius: 11.0)
                        if let invite = item.invite, invitationAvailability(invite).isZero {
                            shareButtonNode.title = item.presentationData.strings.InviteLink_ReactivateLink
                        } else {
                            shareButtonNode.title = effectiveSeparateButtons ? item.presentationData.strings.InviteLink_ShareShort : item.presentationData.strings.InviteLink_Share
                        }
                        shareButtonNode.pressed = { [weak self] in
                            self?.item?.shareAction?()
                        }
                        strongSelf.addSubnode(shareButtonNode)
                        strongSelf.shareButtonNode = shareButtonNode
                    }
                    
                    let buttonSpacing: CGFloat = 8.0
                    var buttonWidth = contentSize.width - leftInset - rightInset
                    var shareButtonOriginX = leftInset
                    if effectiveSeparateButtons {
                        buttonWidth = (buttonWidth - buttonSpacing) / 2.0
                        shareButtonOriginX = leftInset + buttonWidth + buttonSpacing
                    }
                    
                    let _ = copyButtonNode.updateLayout(width: buttonWidth, transition: .immediate)
                    copyButtonNode.frame = CGRect(x: leftInset, y: verticalInset + fieldHeight + fieldSpacing, width: buttonWidth, height: buttonHeight)
                    
                    let _ = shareButtonNode.updateLayout(width: buttonWidth, transition: .immediate)
                    shareButtonNode.frame = CGRect(x: shareButtonOriginX, y: verticalInset + fieldHeight + fieldSpacing, width: buttonWidth, height: buttonHeight)

                    if let justCreatedCallTextNodeLayout {
                        if let justCreatedCallTextNode = justCreatedCallTextNodeLayout.1(TextNodeWithEntities.Arguments(
                            context: item.context,
                            cache: item.context.animationCache,
                            renderer: item.context.animationRenderer,
                            placeholderColor: .gray,
                            attemptSynchronous: true
                        )) {
                            if strongSelf.justCreatedCallTextNode !== justCreatedCallTextNode {
                                strongSelf.justCreatedCallTextNode?.textNode.removeFromSupernode()
                                strongSelf.justCreatedCallTextNode = justCreatedCallTextNode
                                
                                strongSelf.addSubnode(justCreatedCallTextNode.textNode)
                                
                                justCreatedCallTextNode.textNode.view.addGestureRecognizer(UITapGestureRecognizer(target: strongSelf, action: #selector(strongSelf.justCreatedCallTextTap(_:))))
                            }
                            
                            let justCreatedCallTextNodeFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((params.width - justCreatedCallTextNodeLayout.0.size.width) / 2.0), y: shareButtonNode.frame.maxY + justCreatedCallTextSpacing), size: CGSize(width: justCreatedCallTextNodeLayout.0.size.width, height: justCreatedCallTextNodeLayout.0.size.height))
                            justCreatedCallTextNode.textNode.frame = justCreatedCallTextNodeFrame

                            let justCreatedCallSeparatorText: ComponentView<Empty>
                            if let current = strongSelf.justCreatedCallSeparatorText {
                                justCreatedCallSeparatorText = current
                            } else {
                                justCreatedCallSeparatorText = ComponentView()
                                strongSelf.justCreatedCallSeparatorText = justCreatedCallSeparatorText
                            }
                            
                            let justCreatedCallLeftSeparatorLayer: SimpleLayer
                            if let current = strongSelf.justCreatedCallLeftSeparatorLayer {
                                justCreatedCallLeftSeparatorLayer = current
                            } else {
                                justCreatedCallLeftSeparatorLayer = SimpleLayer()
                                strongSelf.justCreatedCallLeftSeparatorLayer = justCreatedCallLeftSeparatorLayer
                                strongSelf.layer.addSublayer(justCreatedCallLeftSeparatorLayer)
                            }
                            
                            let justCreatedCallRightSeparatorLayer: SimpleLayer
                            if let current = strongSelf.justCreatedCallRightSeparatorLayer {
                                justCreatedCallRightSeparatorLayer = current
                            } else {
                                justCreatedCallRightSeparatorLayer = SimpleLayer()
                                strongSelf.justCreatedCallRightSeparatorLayer = justCreatedCallRightSeparatorLayer
                                strongSelf.layer.addSublayer(justCreatedCallRightSeparatorLayer)
                            }
                            
                            justCreatedCallLeftSeparatorLayer.backgroundColor = item.presentationData.theme.list.itemPlainSeparatorColor.cgColor
                            justCreatedCallRightSeparatorLayer.backgroundColor = item.presentationData.theme.list.itemPlainSeparatorColor.cgColor
                            
                            let justCreatedCallSeparatorTextSize = justCreatedCallSeparatorText.update(
                                transition: .immediate,
                                component: AnyComponent(MultilineTextComponent(
                                    text: .plain(NSAttributedString(string: item.presentationData.strings.SendInviteLink_PremiumOrSendSectionSeparator, font: Font.regular(15.0), textColor: item.presentationData.theme.list.itemSecondaryTextColor))
                                )),
                                environment: {},
                                containerSize: CGSize(width: params.width - leftInset - rightInset, height: 100.0)
                            )
                            let justCreatedCallSeparatorTextFrame = CGRect(origin: CGPoint(x: floor((params.width - justCreatedCallSeparatorTextSize.width) * 0.5), y: shareButtonNode.frame.maxY + justCreatedCallSeparatorSpacing), size: justCreatedCallSeparatorTextSize)
                            if let justCreatedCallSeparatorTextView = justCreatedCallSeparatorText.view {
                                if justCreatedCallSeparatorTextView.superview == nil {
                                    strongSelf.view.addSubview(justCreatedCallSeparatorTextView)
                                }
                                justCreatedCallSeparatorTextView.frame = justCreatedCallSeparatorTextFrame
                            }
                            
                            let separatorWidth: CGFloat = 72.0
                            let separatorSpacing: CGFloat = 10.0
                            
                            justCreatedCallLeftSeparatorLayer.frame = CGRect(origin: CGPoint(x: justCreatedCallSeparatorTextFrame.minX - separatorSpacing - separatorWidth, y: justCreatedCallSeparatorTextFrame.midY + 1.0), size: CGSize(width: separatorWidth, height: UIScreenPixel))
                            justCreatedCallRightSeparatorLayer.frame = CGRect(origin: CGPoint(x: justCreatedCallSeparatorTextFrame.maxX + separatorSpacing, y: justCreatedCallSeparatorTextFrame.midY + 1.0), size: CGSize(width: separatorWidth, height: UIScreenPixel))
                        }
                    } else if let justCreatedCallTextNode = strongSelf.justCreatedCallTextNode {
                        strongSelf.justCreatedCallTextNode = nil
                        justCreatedCallTextNode.textNode.removeFromSupernode()

                        strongSelf.justCreatedCallLeftSeparatorLayer?.removeFromSuperlayer()
                        strongSelf.justCreatedCallLeftSeparatorLayer = nil

                        strongSelf.justCreatedCallRightSeparatorLayer?.removeFromSuperlayer()
                        strongSelf.justCreatedCallRightSeparatorLayer = nil

                        strongSelf.justCreatedCallSeparatorText?.view?.removeFromSuperview()
                        strongSelf.justCreatedCallSeparatorText = nil
                    }
                    
                    var totalWidth = invitedPeersLayout.size.width
                    var leftOrigin: CGFloat = floorToScreenPixels((params.width - invitedPeersLayout.size.width) / 2.0)
                    let avatarSpacing: CGFloat = 21.0
                    if let avatarsContent = strongSelf.avatarsContent {
                        let avatarsSize = strongSelf.avatarsNode.update(context: item.context, content: avatarsContent, itemSize: CGSize(width: 32.0, height: 32.0), animated: true, synchronousLoad: true)
                        
                        if !avatarsSize.width.isZero {
                            totalWidth += avatarsSize.width + avatarSpacing
                        }
                        
                        let avatarsNodeFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((params.width - totalWidth) / 2.0), y: fieldFrame.maxY + 87.0), size: avatarsSize)
                        strongSelf.avatarsNode.frame = avatarsNodeFrame
                        if !avatarsSize.width.isZero {
                            leftOrigin = avatarsNodeFrame.maxX + avatarSpacing
                        }
                    }
                    
                    strongSelf.invitedPeersNode.frame = CGRect(origin: CGPoint(x: leftOrigin, y: fieldFrame.maxY + 92.0), size: invitedPeersLayout.size)
                    
                    strongSelf.avatarsButtonNode.frame = CGRect(x: floorToScreenPixels((params.width - totalWidth) / 2.0), y: fieldFrame.maxY + 87.0, width: totalWidth, height: 32.0)
                    strongSelf.avatarsButtonNode.isUserInteractionEnabled = !item.peers.isEmpty && item.invite != nil
                    
                    strongSelf.addressButtonNode.isUserInteractionEnabled = item.invite != nil
                    strongSelf.fieldButtonNode.isUserInteractionEnabled = item.invite != nil
                    strongSelf.addressButtonIconNode.alpha = item.invite != nil ? 1.0 : 0.0
                    
                    
                    strongSelf.copyButtonNode?.isUserInteractionEnabled = item.invite != nil
                    strongSelf.copyButtonNode?.alpha = item.invite != nil ? 1.0 : 0.4
                    strongSelf.copyButtonNode?.isHidden = !item.displayButton || !effectiveSeparateButtons
                    
                    strongSelf.shareButtonNode?.isUserInteractionEnabled = item.invite != nil
                    strongSelf.shareButtonNode?.alpha = item.invite != nil ? 1.0 : 0.4
                    strongSelf.shareButtonNode?.isHidden = !item.displayButton
                    
                    strongSelf.avatarsButtonNode.isHidden = !item.displayImporters
                    strongSelf.avatarsNode.isHidden = !item.displayImporters || item.invite == nil
                    strongSelf.invitedPeersNode.isHidden = !item.displayImporters || item.invite == nil
                    
                    if item.invite == nil {
                        let shimmerNode: ShimmerEffectNode
                        if let current = strongSelf.shimmerNode {
                            shimmerNode = current
                        } else {
                            shimmerNode = ShimmerEffectNode()
                            strongSelf.shimmerNode = shimmerNode
                            strongSelf.insertSubnode(shimmerNode, belowSubnode: strongSelf.fieldNode)
                        }
                        shimmerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
                        if let (rect, size) = strongSelf.absoluteLocation {
                            shimmerNode.updateAbsoluteRect(rect, within: size)
                        }
                        
                        let lineWidth: CGFloat = 180.0
                        let lineDiameter: CGFloat = 12.0
                        let titleFrame = strongSelf.invitedPeersNode.frame
                        
                        var shapes: [ShimmerEffectNode.Shape] = []
                        shapes.append(.roundedRectLine(startPoint: CGPoint(x: floor(titleFrame.center.x - lineWidth / 2.0), y: titleFrame.minY + floor((titleFrame.height - lineDiameter) / 2.0)), width: lineWidth, diameter: lineDiameter))
                        shimmerNode.update(backgroundColor: item.presentationData.theme.list.itemBlocksBackgroundColor, foregroundColor: item.presentationData.theme.list.mediaPlaceholderColor, shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, size: layout.contentSize)
                        
                        let addressShimmerNode: ShimmerEffectNode
                        if let current = strongSelf.addressShimmerNode {
                            addressShimmerNode = current
                        } else {
                            addressShimmerNode = ShimmerEffectNode()
                            strongSelf.addressShimmerNode = addressShimmerNode
                            strongSelf.insertSubnode(addressShimmerNode, aboveSubnode: strongSelf.fieldNode)
                        }
                        addressShimmerNode.frame = strongSelf.fieldNode.frame.insetBy(dx: 18.0, dy: 0.0)
                        if let (rect, size) = strongSelf.absoluteLocation {
                            addressShimmerNode.updateAbsoluteRect(CGRect(x: rect.minX + strongSelf.fieldNode.frame.minX + 18.0, y: rect.minY + strongSelf.fieldNode.frame.minY, width: strongSelf.fieldNode.frame.width - 18.0 * 2.0, height: strongSelf.fieldNode.frame.height), within: size)
                        }
                        
                        let addressLineWidth: CGFloat = strongSelf.fieldNode.frame.width - 100.0
                        var addressShapes: [ShimmerEffectNode.Shape] = []
                        addressShapes.append(.roundedRectLine(startPoint: CGPoint(x: floor(addressShimmerNode.frame.width / 2.0 - addressLineWidth / 2.0), y: 16.0 + floor((22.0 - lineDiameter) / 2.0)), width: addressLineWidth, diameter: lineDiameter))
                        addressShimmerNode.update(backgroundColor: item.presentationData.theme.list.itemInputField.backgroundColor, foregroundColor: item.presentationData.theme.list.itemInputField.controlColor.mixedWith(item.presentationData.theme.list.itemInputField.backgroundColor, alpha: 0.7), shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: addressShapes, size: addressShimmerNode.frame.size)

                    } else {
                        if let shimmerNode = strongSelf.shimmerNode {
                            strongSelf.shimmerNode = nil
                            shimmerNode.removeFromSupernode()
                        }
                        if let shimmerNode = strongSelf.addressShimmerNode {
                            strongSelf.shimmerNode = nil
                            shimmerNode.removeFromSupernode()
                        }
                    }
                }
            })
        }
    }
    
    override public func animateInsertion(_ currentTimestamp: Double, duration: Double, options: ListViewItemAnimationOptions) {
        self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
    }
    
    override public func animateAdded(_ currentTimestamp: Double, duration: Double) {
        self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
    }
    
    override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
        self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
    }
    
    override public func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
        var rect = rect
        rect.origin.y += self.insets.top
        self.absoluteLocation = (rect, containerSize)
        if let shimmerNode = self.addressShimmerNode {
            shimmerNode.updateAbsoluteRect(CGRect(x: rect.minX + self.fieldNode.frame.minX + 18.0, y: rect.minY + self.fieldNode.frame.minY, width: self.fieldNode.frame.width - 18.0 * 2.0, height: self.fieldNode.frame.height), within: containerSize)
        }
        if let shimmerNode = self.shimmerNode {
            shimmerNode.updateAbsoluteRect(rect, within: containerSize)
        }
    }
}
